package server

import (
	"encoding/json"
	"errors"
)

const protocolVersion = "2.0"

type Message interface {
	IsJSONRPC() bool
}

type Request struct {
	ProtocolVersion string           `json:"jsonrpc"`
	ID              *json.RawMessage `json:"id"`
	Method          string           `json:"method"`
	Params          json.RawMessage  `json:"params"`
}

func (r Request) IsJSONRPC() bool {
	return r.ProtocolVersion == protocolVersion
}

func (r Request) IsNotification() bool {
	return r.ID == nil
}

type Response struct {
	ProtocolVersion string           `json:"jsonrpc"`
	ID              *json.RawMessage `json:"id"`
	Result          any              `json:"result"`
	Error           *Error           `json:"error"`
}

func (r Response) IsJSONRPC() bool {
	return r.ProtocolVersion == protocolVersion
}

type Error struct {
	// Code is a Number that indicates the error type that occurred.
	Code int64 `json:"code"`
	// Message of the error.
	// The message SHOULD be limited to a concise single sentence.
	Message string `json:"message"`
	// A Primitive or Structured value that contains additional information about the error.
	// This may be omitted.
	// The value of this member is defined by the Server (e.g. detailed error information, nested errors etc.).
	Data any `json:"data"`
}

func (e *Error) Error() string {
	return e.Message
}

var (
	ErrParseError           = &Error{Code: -32700, Message: "Parse error"}
	ErrInvalidRequest       = &Error{Code: -32600, Message: "Invalid Request"}
	ErrMethodNotFound       = &Error{Code: -32601, Message: "Method not found"}
	ErrInvalidParams        = &Error{Code: -32602, Message: "Invalid params"}
	ErrInternal             = &Error{Code: -32603, Message: "Internal error"}
	ErrServerNotInitialized = &Error{Code: -32002, Message: "Server not initialized"}
)
var ErrInvalidContentLengthHeader = errors.New("missing or invalid Content-Length header")

func NewResponseError(id *json.RawMessage, err error) Response {
	return Response{
		ProtocolVersion: protocolVersion,
		ID:              id,
		Result:          nil,
		Error:           newError(err),
	}
}

func newError(err error) *Error {
	if err == nil {
		return nil
	}
	var e *Error
	if errors.As(err, &e) {
		return e
	}
	return &Error{
		Code:    0,
		Message: err.Error(),
		Data:    nil,
	}
}

func NewResponse(id *json.RawMessage, result any) Response {
	return Response{
		ProtocolVersion: protocolVersion,
		ID:              id,
		Result:          result,
		Error:           nil,
	}
}

type Notification struct {
	ProtocolVersion string `json:"jsonrpc"`
	Method          string `json:"method"`
	Params          any    `json:"params"`
}

func (n Notification) IsJSONRPC() bool {
	return n.ProtocolVersion == protocolVersion
}
